﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OVS.BusinessObjects;
using OVS.BLL;
using log4net;
using OVS_ApplicationConfiguration.Manager;
using System.Windows;
using System.Collections;
using System.Windows.Controls;
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.CV.CvEnum;
using Emgu.CV.UI;
using System.Threading;
using MjpegProcessor;
using Emgu.CV.GPU;
using System.Diagnostics;
using OVS_Tools;
using OVS_FormsRecognition.Objects;
using System.IO;
using Cudafy;
using Cudafy.Host;
using Cudafy.Translator;
using System.Threading.Tasks;
using System.Drawing;
using System.Windows.Threading;


namespace OVS_FormsRecognition.Manager
{
    /// <summary>
    /// Manager permetant de gérer la détection d'objet dans une caméra
    /// </summary>
    public class FormsRecognitionManager
    {
        #region Attr Logger
        /// <summary>
        /// Logger par défaut du ManagerUtilisateurs
        /// </summary>
        private static readonly log4net.ILog _Log = log4net.LogManager.GetLogger(typeof(FormsRecognitionManager));
        #endregion

        #region Attributs
        private ListView _listCams;
        private List<Camera> listCameras;
        private static MjpegDecoder _mjpeg;
        private static Stopwatch watch;

        private int imdeID;
        private Thread workerDectorThread;

        private static SynchronizationContext synchronizationContext;


        private int currentCamId;
        private string currentCamPath;

        public List<CameraFromMjpegDecoder> listCamera { get; set; }

        private Dictionary<int, TimerEndAlert> listTimerEndAlert { get; set; }

        public const int TimeForEndAlerteInMiliseconde = 20 * 1000;

        static readonly object padlockGPU = new object();

        /// <summary>
        /// The dic event waiting to start
        /// dico par camID contenant la liste des event par threadID
        /// </summary>
        Dictionary<int, Dictionary<int, ProcessDetectEventArgs>> dicEventWaitingToStart = new Dictionary<int, Dictionary<int, ProcessDetectEventArgs>>();

        #endregion

        #region Gestion du singleton

        /// <summary>
        /// Instance locale pour héberger le singleton
        /// </summary>
        static FormsRecognitionManager instance = null;

        /// <summary>
        /// Objet permettant la gestion des LOCK lors de l'instanciation
        /// </summary>
        static readonly object padlock = new object();

        /// <summary>
        /// Constructeur par défaut
        /// </summary>
        FormsRecognitionManager()
        {
            if (_Log.IsDebugEnabled)
                _Log.DebugFormat("Nouvelle instance de '{0}'", this.GetType().ToString());

            listCamera = new List<CameraFromMjpegDecoder>();
            synchronizationContext = System.Threading.SynchronizationContext.Current;
            listTimerEndAlert = new Dictionary<int, TimerEndAlert>();
        }

        /// <summary>
        /// Déclaration unique par gestion du singleton
        /// </summary>
        public static FormsRecognitionManager Instance
        {
            get
            {
                lock (padlock)
                {
                    if (instance == null)
                    {
                        instance = new FormsRecognitionManager();
                    }
                    return instance;
                }
            }
        }

        #endregion Gestion du singleton


        #region initialisation des caméra
        /// <summary>
        /// Adds the new camera.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <param name="camPath">The cam path.</param>
        public void AddNewCamera(int id, string camPath)
        {

            try
            {
                CameraFromMjpegDecoder currentCameraFromMjpegDecoder = new CameraFromMjpegDecoder(id, camPath);
                currentCameraFromMjpegDecoder.InitObject();
                instance.listCamera.Add(currentCameraFromMjpegDecoder);
            }
            catch (Exception ex)
            {
                _Log.WarnFormat("WorkerAddNewCamera(camId): Exception {2}", ex);
            }

        }
        #endregion


        #region Déclaration des évènements

        #region Object Detect Finished
        // Declare the delegate (if using non-generic pattern).
        public delegate void ObjectDetectFinishedEventHandler(object sender, DetectEventArgs e);

        //// Declare the event.
        public event ObjectDetectFinishedEventHandler ObjectDetectFinishedEvent;
        #endregion

        #region Size Calculation
        // Declare the delegate (if using non-generic pattern).
        //public delegate void SizeCalculationEventHandler(object sender, SizeCalculationEventArgs e);

        //// Declare the event.
        //public event SizeCalculationEventHandler SizeCalculationStartEvent;
        #endregion

        #region Trajectory Calculation
        // Declare the delegate (if using non-generic pattern).
        public delegate void TrajectoryCalculationEventHandler(object sender, TrajectoryCalculationEventArgs e);

        // Declare the event.
        public event TrajectoryCalculationEventHandler TrajectoryCalculationEventNewCapture;

        // Declare the event.
        public event TrajectoryCalculationEventHandler TrajectoryCalculationEventStopCapture;
        #endregion

        #region Video Recorder
        // Declare the delegate (if using non-generic pattern).
        public delegate void VideoRecorderEventHandler(object sender, VideoRecorderEventArgs e);

        // Declare the event.
        public event VideoRecorderEventHandler VideoRecorderEventNewFrame;

        // Declare the event.
        public event VideoRecorderEventHandler VideoRecorderEventStopSaveVideo;
        #endregion

        #region Notification Sender
        // Declare the delegate (if using non-generic pattern).
        public delegate void NotificationSenderEventHandler(object sender, NotificationSenderEventArgs e);

        // Declare the event.
        public event NotificationSenderEventHandler NotificationSenderEventStart;

        #endregion

        #region Update Camera
        // Declare the delegate (if using non-generic pattern).
        public delegate void UpdateCameraDetectionSenderEventHandler(object sender, ProcessDetectEventArgs e);

        // Declare the event.
        public event UpdateCameraDetectionSenderEventHandler UpdateCameraDetectionSenderEvent;
        private Action<string> SetStatus;
        private int currentGPUid = -1;

        #endregion

        #endregion


        #region Raise Event



        ///// <summary>
        ///// Raises the video recorder event new frame.
        ///// </summary>
        ///// <param name="newAlerteStarted">The new alerte started.</param>
        //protected virtual void RaiseObjectDetectionFinished(int camId, Image_Haar HaartainningFile, Image<Bgr, byte> frame, Nullable<Rectangle> rec)
        //{
        //    DetectEventArgs paramObj = new DetectEventArgs();
        //    paramObj.camId = camId;
        //    paramObj.detectHaar = HaartainningFile;
        //    paramObj.detectFrame = frame;
        //    if (rec != null)
        //        paramObj.detectRec = (Rectangle)rec;
        //    // Raise the event by using the () operator.
        //    ObjectDetectFinishedEvent(this, paramObj);
        //}

        /// <summary>
        /// Raises the size calculation start event.
        /// </summary>
        /// <param name="newAlerteStarted">The new alerte started.</param>
        //protected virtual void RaiseSizeCalculationStartEvent(Alert newAlerteStarted, Image<Bgr, byte> frame, Rectangle rec, int img_haar_id)
        //{
        //    SizeCalculationEventArgs paramObj = new SizeCalculationEventArgs();
        //    paramObj.sceImage = frame;
        //    paramObj.sceRect = rec;
        //    paramObj.img_haar_id = img_haar_id;
        //    paramObj.alertId = newAlerteStarted.aler_id;

        //    // paramObj.img_id = newAlerteStarted.
        //    // Raise the event by using the () operator.
        //    SizeCalculationStartEvent(this, paramObj);
        //}

        /// <summary>
        /// Raises the trajectory calculation event new capture.
        /// </summary>
        /// <param name="newAlerteStarted">The new alerte started.</param>
        protected virtual void RaiseTrajectoryCalculationEventNewCapture(Alert newAlerteStarted, Image<Bgr, byte> frame, Rectangle rec)
        {
            // Raise the event by using the () operator.
            TrajectoryCalculationEventArgs pTrajectoryCalculationEventArgs = new TrajectoryCalculationEventArgs();
            pTrajectoryCalculationEventArgs.Id_Alert = newAlerteStarted.aler_id;
            pTrajectoryCalculationEventArgs.Image_Detecte = frame;
            pTrajectoryCalculationEventArgs.Rect = rec;

            TrajectoryCalculationEventNewCapture(this, pTrajectoryCalculationEventArgs);

        }



        /// <summary>
        /// Raises the trajectory calculation event stop capture.
        /// </summary>
        /// <param name="newAlerteStarted">The new alerte started.</param>
        protected virtual void RaiseTrajectoryCalculationEventStopCapture(int alert_id)
        {
            // Raise the event by using the () operator.
            TrajectoryCalculationEventArgs pTrajectoryCalculationEventArgs = new TrajectoryCalculationEventArgs();
            pTrajectoryCalculationEventArgs.Id_Alert = alert_id;
            TrajectoryCalculationEventStopCapture(this, pTrajectoryCalculationEventArgs);
        }



        /// <summary>
        /// Raises the video recorder event new frame.
        /// </summary>
        /// <param name="newAlerteStarted">The new alerte started.</param>
        protected virtual void RaiseVideoRecorderEventNewFrame(Alert newAlerteStarted, Image<Bgr, byte> frame)
        {
            VideoRecorderEventArgs paramObj = new VideoRecorderEventArgs();
            paramObj.id_alert = newAlerteStarted.aler_id;
            paramObj.ImageFrame = frame;
            // Raise the event by using the () operator.
            VideoRecorderEventNewFrame(this, paramObj);
        }



        /// <summary>
        /// Raises the video recorder event stop save video.
        /// </summary>
        /// <param name="newAlerteStarted">The new alerte started.</param>
        protected virtual void RaiseVideoRecorderEventStopSaveVideo(int alert_id)
        {
            // Raise the event by using the () operator.
            VideoRecorderEventArgs pVideoRecorderEventArgs = new VideoRecorderEventArgs();
            pVideoRecorderEventArgs.id_alert = alert_id;

            VideoRecorderEventStopSaveVideo(this, pVideoRecorderEventArgs);
        }



        /// <summary>
        /// Raises the notification sender event start.
        /// </summary>
        /// <param name="newAlerteStarted">The new alerte started.</param>
        protected virtual void RaiseNotificationSenderEventStart(int alert_id)
        {
            NotificationSenderEventArgs notif = new NotificationSenderEventArgs();
            notif.id_alert = alert_id;
            // Raise the event by using the () operator.
            NotificationSenderEventStart(this, notif);
        }


        /// <summary>
        /// Raises the update camera detection.
        /// </summary>
        /// <param name="eventArgs">The <see cref="ProcessDetectEventArgs"/> instance containing the event data.</param>
        public virtual void RaiseUpdateCameraDetection(ProcessDetectEventArgs eventArgs)
        {
            Thread th = new Thread(RaiseNewFrame);
            th.Start(eventArgs);

        }

        private bool EventIsReadyToRaise(ProcessDetectEventArgs eventArgs)
        {
            // Ajout de l'argument dans une liste d'event à lancer
            if (dicEventWaitingToStart.ContainsKey(eventArgs.camId))
            {
                try
                {
                    ProcessDetectEventArgs previousEvent = dicEventWaitingToStart[eventArgs.camId][(eventArgs.ThreadId - 1)];
                    if (previousEvent.camera.pool[previousEvent.ThreadId].isFinished)
                    {
                        _Log.DebugFormat("Le thread id {0} est terminé, ajout de l'évènement suivant dans la pile!", previousEvent.ThreadId);
                        dicEventWaitingToStart[eventArgs.camId].Add(eventArgs.ThreadId, eventArgs);
                        _Log.DebugFormat("Suppression du thread id {0} de la pile...", previousEvent.ThreadId);
                        return true;
                    }
                    else
                    {
                        _Log.DebugFormat("Le thread id {0} n'est pas terminé", previousEvent.ThreadId);
                        return false;
                    }
                }
                catch (Exception)
                {
                    _Log.DebugFormat("Le thread id {0} n'est pas encore dans la pile!", eventArgs.ThreadId - 1);

                    return false;
                }

            }
            else
            {
                _Log.DebugFormat("Première apple pour la caméra id: {0}", eventArgs.camId);
                dicEventWaitingToStart.Add(eventArgs.camId, new Dictionary<int, ProcessDetectEventArgs>());
                dicEventWaitingToStart[eventArgs.camId].Add(eventArgs.ThreadId, eventArgs);
                return true;

            }

        }

        /// <summary>
        /// Processes the frame.
        /// </summary>
        /// <param name="stateInfo">The state info.</param>
        public void RaiseNewFrame(object param)
        {
            lock (this)
            {               
                ProcessDetectEventArgs eventArgs = param as ProcessDetectEventArgs;

                if (!eventArgs.isInTestMode)
                {

                    //while (!EventIsReadyToRaise(eventArgs))
                    //{
                    //    _Log.Debug("wait...event finish");
                    //}
                    //_Log.Debug("Raise...event threadID: " + eventArgs.ThreadId);

                    if (eventArgs.camera.detectObject)
                    {
                        if (eventArgs.dicDetectObjects.Count <= 0)
                        {
                            foreach (Image_Haar item in eventArgs.listHaarFilesToDetect)
                            {
                                UpdateCameraVideoFrameWithNoObjectDetected(eventArgs.camId, item, eventArgs.detectFrame.Clone());
                            }

                        }
                        else
                        {
                            foreach (KeyValuePair<Image_Haar, Rectangle[]> item in eventArgs.dicDetectObjects)
                            {
                                foreach (Rectangle rec in item.Value)
                                {
                                    setObjectDetected(eventArgs.camId, item.Key, eventArgs.detectFrame.Clone(), rec);
                                }

                            }

                        }
                    }
                }
                //if (eventArgs.detectFrame != null)
                //    eventArgs.detectFrame.Dispose();

                // Raise the event by using the () operator.
                UpdateCameraDetectionSenderEvent(this, eventArgs);
            }
        }


        #endregion


        #region Analyse de la frame

        /// <summary>
        /// Detects the object.
        /// </summary>
        /// <param name="param">The param.</param>
        public void DetectObject(ProcessDetectEventArgs args, int currentThreadIdInPool)
        {
            lock (this)
            {
                try
                {
                    // Effectue les traitements
                    args = AnalyseFrameFromCamera(args);               

                    FormsRecognitionManager.Instance.RaiseUpdateCameraDetection(args);
                }
                catch (Exception ex)
                {
                    _Log.Fatal("DetectObject: Exception: " + ex);
                }
            }

        }
        /// <summary>
        /// Analyses the frame from camera.
        /// </summary>
        /// <param name="detectObject">if set to <c>true</c> [detect object].</param>
        /// <param name="camId">The cam id.</param>
        /// <param name="bitmapImage">The bitmap image.</param>
        /// <param name="HaartainningFiles">The haartainning files.</param>
        /// <param name="scaleFactor">The scale factor.</param>
        /// <param name="minNeighbors">The min neighbors.</param>
        /// <returns></returns>
        public ProcessDetectEventArgs AnalyseFrameFromCamera(ProcessDetectEventArgs args)
        {
            args.detectFrame = new Image<Bgr, Byte>(args.bitmapSource);

            if (args.camera.detectObject)
            {
                return instance.ProcessGPUDetection(args);
            }
            else
            {
                args.bitmapFromdetection = args.camera.currentFrame;
                return args;
            }
        }

        /// <summary>
        /// Processes the GPU detection.
        /// </summary>
        /// <param name="camId">The cam id.</param>
        /// <param name="pHaartainningFiles">The p haartainning files.</param>
        /// <param name="frame">The frame.</param>
        /// <param name="scaleFactor">The scale factor.</param>
        /// <param name="minNeighbors">The min neighbors.</param>
        /// <returns></returns>
        private ProcessDetectEventArgs ProcessGPUDetection(ProcessDetectEventArgs args)
        {
            //lock (this)
            {
                if (args.listHaarFilesToDetect == null)
                    return args;

                try
                {

                    watch = Stopwatch.StartNew();
                    int colorvalueB = 10;

                    Dictionary<Image_Haar, Rectangle[]> listRectangleDetected = new Dictionary<Image_Haar, Rectangle[]>();

                    // Analyse de l'images pour tous les descripteur d'objets
                    foreach (var haartainningfile in args.listHaarFilesToDetect)
                    {                        
                        {
                            Rectangle[] recdetected = instance.ProcessGPUDetection(args.detectFrame, args, args.dicDetectObjects, haartainningfile, colorvalueB, Convert.ToDouble(haartainningfile.imha_scaleFactor), Convert.ToInt32(haartainningfile.imha_minNeighbors), true);
                            if (recdetected != null && recdetected.Length > 0)
                                listRectangleDetected.Add(haartainningfile, recdetected);
                        }
                    }
                  
                    // dessin des objets détecté
                    foreach (var detectRegion in listRectangleDetected)
                    {
                        if (detectRegion.Value.Length <= 0)
                        {

                        }
                        else
                        {
                            foreach (Rectangle e in detectRegion.Value)
                            {                              
                                //draw the face detected in the 0th (gray) channel with blue color
                                args.detectFrame.Draw(e, new Bgr(255, colorvalueB, 0), 2);
                            }
                            args.dicDetectObjects.Add(detectRegion.Key, detectRegion.Value);
                        }
                        colorvalueB = colorvalueB + 100;
                    }

                    args.bitmapFromdetection = args.detectFrame.ToBitmap();
                    watch.Stop();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("ProcessGPUDetection: Exception: " + ex);
                }
            }


            return args;
        }


        /// <summary>
        /// Processes the GPU detection.
        /// </summary>
        /// <param name="camId">The cam id.</param>
        /// <param name="HaartainningFile">The haartainning file.</param>
        /// <param name="frame">The frame.</param>
        /// <param name="colorvalueB">The colorvalue B.</param>
        /// <param name="scaleFactor">The scale factor.</param>
        /// <param name="minNeighbors">The min neighbors.</param>
        /// <returns></returns>
        public Rectangle[] ProcessGPUDetection(Emgu.CV.Image<Emgu.CV.Structure.Bgr, byte> frame, ProcessDetectEventArgs args, Dictionary<Image_Haar, Rectangle[]> dicDetectObjects, Image_Haar HaartainningFile, int colorvalueB, double scaleFactor, int minNeighbors, bool RaiseEvent)
        {
            Rectangle[] detectRegion = null;

            lock (this)
            {
                if (GpuInvoke.HasCuda)
                {
                    int numberOfCudaGPUEnable = GpuInvoke.GetCudaEnabledDeviceCount();
                    currentGPUid++;
                    if (currentGPUid >= numberOfCudaGPUEnable)
                        currentGPUid = 0;
                    GpuInvoke.SetDevice(currentGPUid);


                    if (!String.IsNullOrEmpty(HaartainningFile.imha_fn))
                    {

                        using (GpuCascadeClassifier haatrainingObject = new GpuCascadeClassifier(HaartainningFile.imha_fn))
                        {
                            using (GpuImage<Bgr, Byte> gpuImage = new GpuImage<Bgr, byte>(frame))
                            using (GpuImage<Gray, Byte> gpuGray = gpuImage.Convert<Gray, Byte>())
                            {
                                //For some reason a clone is required.
                                //Might be a bug of GpuCascadeClassifier in opencv
                                using (GpuImage<Gray, Byte> clone = gpuGray.Clone())
                                {

                                    System.Drawing.Size minSize = System.Drawing.Size.Empty;
                                    if (HaartainningFile.imha_height != null)
                                        minSize.Height = (int)HaartainningFile.imha_height;

                                    if (HaartainningFile.imha_width != null)
                                        minSize.Width = (int)HaartainningFile.imha_width;

                                    detectRegion = haatrainingObject.DetectMultiScale(clone, scaleFactor, minNeighbors, minSize);

                                }
                                haatrainingObject.Dispose();
                            }
                        }
                    }
                }
                else
                {
                    _Log.Error("GPU Non Disponible !!!! Calcul via le CPU TODO implement");
                    //ProcessCPUDetection(camId, HaartainningFile, frame, colorvalueB, scaleFactor, minNeighbors, RaiseEvent);
                }

                //args.bitmapFromdetection = args.detectFrame.ToBitmap();
                return detectRegion;
            }
        }

        ///// <summary>
        ///// Processes the GPU detection.
        ///// </summary>
        ///// <param name="camId">The cam id.</param>
        ///// <param name="HaartainningFile">The haartainning file.</param>
        ///// <param name="frame">The frame.</param>
        ///// <param name="colorvalueB">The colorvalue B.</param>
        ///// <param name="scaleFactor">The scale factor.</param>
        ///// <param name="minNeighbors">The min neighbors.</param>
        ///// <returns></returns>
        //public Bitmap ProcessCPUDetection(int camId, Image_Haar HaartainningFile, Image<Bgr, byte> frame, int colorvalueB, double scaleFactor, int minNeighbors, bool RaiseEvent)
        //{
        //    lock (this)
        //    {
        //        colorvalueB = colorvalueB + 100;
        //        if (!String.IsNullOrEmpty(HaartainningFile.imha_fn))
        //        {
        //            //using (GpuCascadeClassifier haatrainingObject = new GpuCascadeClassifier(HaartainningFile.imha_fn))
        //            {
        //                using (HaarCascade haatrainingObject = new HaarCascade(HaartainningFile.imha_fn))
        //                using (Image<Gray, Byte> gpuGray = frame.Convert<Gray, Byte>()) //Convert it to Grayscale
        //                {
        //                    ////For some reason a clone is required.
        //                    ////Might be a bug of GpuCascadeClassifier in opencv
        //                    //using (GpuImage<Gray, Byte> clone = gpuGray.Clone())
        //                    {
        //                        gpuGray._EqualizeHist();

        //                        System.Drawing.Size minSize = System.Drawing.Size.Empty;
        //                        if (HaartainningFile.imha_height != null)
        //                            minSize.Height = (int)HaartainningFile.imha_height;

        //                        if (HaartainningFile.imha_width != null)
        //                            minSize.Width = (int)HaartainningFile.imha_width;


        //                        //Rectangle[] eyeRegion = haatrainingObject.DetectMultiScale(clone, scaleFactor, minNeighbors, minSize);
        //                        MCvAvgComp[] detectRegion = haatrainingObject.Detect(
        //       gpuGray,
        //       scaleFactor,
        //       minNeighbors,
        //       Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_CANNY_PRUNING,
        //       minSize,
        //       System.Drawing.Size.Empty);

        //                        if (detectRegion.Length <= 0)
        //                        {
        //                            UpdateCameraVideoFrameWithNoObjectDetected(camId, HaartainningFile, frame);
        //                        }
        //                        else
        //                        {

        //                            foreach (MCvAvgComp MCVe in detectRegion)
        //                            {

        //                                Rectangle e = MCVe.rect;
        //                                //draw the face detected in the 0th (gray) channel with blue color
        //                                frame.Draw(e, new Bgr(255, colorvalueB, 0), 2);

        //                                //this.addObjectInDataGridView(HaartainningFileName);

        //                                if (RaiseEvent)
        //                                    setObjectDetected(camId, HaartainningFile, frame, e);

        //                            }
        //                        }
        //                    }
        //                }
        //            }
        //        }
        //    }
        //    return frame.ToBitmap();
        //}


        /// <summary>
        /// News the update from cam allow.
        /// </summary>
        /// <param name="camera">The camera.</param>
        /// <param name="detectEventArgs">The <see cref="DetectEventArgs" /> instance containing the event data.</param>
        public void NewUpdateFromCamAllow(CameraFromMjpegDecoder camera, ProcessDetectEventArgs detectEventArgs, int currentThreadIdInPool)
        {
            detectEventArgs.camera = camera;
            DetectObject(detectEventArgs, currentThreadIdInPool);
        }
        #endregion


        /// <summary>
        /// Updates the camera video frame with no object detected.
        /// </summary>
        /// <param name="camId">The cam id.</param>
        /// <param name="HaartainningFile">The haartainning file.</param>
        private void UpdateCameraVideoFrameWithNoObjectDetected(int camId, Image_Haar HaartainningFile, Image<Bgr, byte> frame)
        {
           
                Alert lastActiveAlert = AlertBLL.Instance.GetAlertOfCameraAndDetectedObject(camId, HaartainningFile.imha_id, TimeForEndAlerteInMiliseconde);
                if (lastActiveAlert.aler_id > 0)
                {
                    RaiseVideoRecorderEventNewFrame(lastActiveAlert, frame);
                }
            
        }


        #region Nouvelle frame contenant un objet détecté
        /// <summary>
        /// Sets the object detected.
        /// </summary>
        /// <param name="camId">The cam id.</param>
        /// <param name="HaartainningFileName">Name of the haartainning file.</param>
        /// <exception cref="System.NotImplementedException"></exception>
        private void setObjectDetected(int camId, Image_Haar HaartainningFile, Image<Bgr, byte> frame, Rectangle rec)
        {

           
                _Log.Debug("setObjectDetected: " + camId + " : " + HaartainningFile.imha_id);
                // Si l'objet à déjà été détecté dans la même caméra
                Alert lastActiveAlert = AlertBLL.Instance.GetAlertOfCameraAndDetectedObject(camId, HaartainningFile.imha_id, TimeForEndAlerteInMiliseconde);
                if (lastActiveAlert.aler_id <= 0)
                {

                    _Log.Debug("new Alerte: " + camId + " : " + HaartainningFile.imha_id);
                    lastActiveAlert = new Alert();

                    lastActiveAlert.came_id = camId;
                    lastActiveAlert.aler_dt = DateTime.Now;
                    // TODO alerte LVL???
                    lastActiveAlert.aler_lvl = 1;
                    lastActiveAlert.aler_status = false;
                    lastActiveAlert.aler_id = AlertBLL.Instance.AddAlert(lastActiveAlert);

                    //RaiseSizeCalculationStartEvent(lastActiveAlert, frame, rec, HaartainningFile.imha_id);
                    Image_Details objImg = new Image_Details();
                    objImg.imha_id = HaartainningFile.imha_id;
                    objImg.imde_sizeH = 0;
                    objImg.imde_sizeL = 0;

                    imdeID = Image_DetailsBLL.Instance.AddImage_Details(objImg);//ajoute l'objet en base


                    //on recupere imde_id du dernier enregistrement pour mettre à jour l'alerte

                    lastActiveAlert.imde_id = imdeID;
                    //Update de l'alerte !!!! by bubu
                    AlertBLL.Instance.UpdateAlert(lastActiveAlert);

                    startTimerEndAlert(lastActiveAlert.aler_id);
                }
                else
                {
                    _Log.Debug("recup. alert: " + camId + " : " + HaartainningFile.imha_id);
                    // on récupère l'alerte déjà créé
                    updateTimerEndAlert(lastActiveAlert.aler_id);
                }

                //lastActiveAlert.aler_id = 1;

                RaiseVideoRecorderEventNewFrame(lastActiveAlert, frame.Clone());
                RaiseTrajectoryCalculationEventNewCapture(lastActiveAlert, frame.Clone(), rec);

                frame.Dispose();

        }

        private void startTimerEndAlert(int alert_id)
        {
            TimerEndAlert timer = new TimerEndAlert();
            timer.alertId = alert_id;
            timer.Interval = 10 * 1000; // set the interval as 10000 ms
            timer.Elapsed += new System.Timers.ElapsedEventHandler(this.endAlert); // set the event to execute
            timer.AutoReset = false; // false: only execute once
            timer.Enabled = true; // to decide if execute the event of timer specified

            listTimerEndAlert.Add(alert_id, timer);

            _Log.DebugFormat("startTimerEndAlert: idAlert: {0}", alert_id);
        }

        private void updateTimerEndAlert(int alert_id)
        {

            if (!listTimerEndAlert.ContainsKey(alert_id))
                return;

            listTimerEndAlert[alert_id].Enabled = false;
            listTimerEndAlert[alert_id] = null;

            TimerEndAlert timer = new TimerEndAlert();
            timer.alertId = alert_id;
            timer.Interval = TimeForEndAlerteInMiliseconde;
            timer.Elapsed += new System.Timers.ElapsedEventHandler(this.endAlert); // set the event to execute
            timer.AutoReset = false; // false: only execute once
            timer.Enabled = true; // to decide if execute the event of timer specified

            listTimerEndAlert[alert_id] = timer;

            _Log.DebugFormat("updateTimerEndAlert: idAlert: {0}", alert_id);
        }

        private void endAlert(object sender, EventArgs e)
        {
            int alert_id = ((TimerEndAlert)sender).alertId;

            if (alert_id <= 0)
                return;

            endAlert(alert_id);

        }

        private void endAlert(int alert_id)
        {
            _Log.DebugFormat("endAlert: idAlert: {0}", alert_id);
            RaiseVideoRecorderEventStopSaveVideo(alert_id);            
            RaiseTrajectoryCalculationEventStopCapture(alert_id);
            RaiseNotificationSenderEventStart(alert_id);
        }

        public void closeAllAlert()
        {
            foreach (Alert alert in AlertBLL.Instance.GetAlerts())
            {
                if (alert.vide_id == null)
                {
                    endAlert(alert.aler_id);
                }
            }
            AlertBLL.Instance.CloseConnexion();
        }

        #endregion



    }
}
